<template>
  <el-tree
    :data="data"
    show-checkbox
    :node-key="props.value"
    ref="tree"
    :props="props"
    default-expand-all
    check-strictly
    :default-checked-keys="defaultCheckedKeys"
    @check="checkBox"
  >
  </el-tree>
</template>

<script>
export default {
  props: {
    /* 默认勾选的数据 */
    defaultCheckedKeys: {
      type: Array,
      default: []
    },
    /* 展示数据 */
    data: {
      type: Array,
      default: []
    },
    /* 配置项 */
    props: {
      type: Object,
      default: () => ({
        children: 'children',
        label: 'permissionName',
        value: 'id',
        parentValue: 'parentId'
      })
    },
    // 是否关联选父节点
    checkStrictlyParent: {
      type: Boolean,
      default: true
    },
    // 是否关联选子节点
    checkStrictlyChildren: {
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      parent: [],
      children: [],
      newTreeList: []
    }
  },
  methods: {
    // 扁平化数据，方便使用
    getNewArray(source) {
      source.forEach((el) => {
        this.newTreeList.push(el)
        el[this.props.children] && el[this.props.children].length > 0
          ? this.getNewArray(el[this.props.children])
          : ''
      })
    },
    // 找到父级数据
    getParent(obj) {
      if (!!obj && obj[this.props.parentValue]) {
        this.parent.push(obj[this.props.parentValue])
        const parent = this.newTreeList.filter(
          (o) => o[this.props.value] === obj[this.props.parentValue]
        )[0]
        this.getParent(parent)
      }
      return this.parent
    },
    // 找打子级数据
    getChildren(obj) {
      if (obj[this.props.children]) {
        obj[this.props.children].map((o) => this.getChildren(o))
      }
      this.children.push(obj[this.props.value])
      return this.children
    },
    async checkBox(obj, data) {
      this.children = []
      this.parent = []
      const getCheckedKeys = this.$refs.tree.getCheckedKeys()
      const children = this.getChildren(obj, false).filter(
        (o) => o != obj[this.props.value]
      )
      if (data.checkedKeys.includes(obj[this.props.value])) {
        // 之前放在监听里面处理，有些情况没考虑放到，所以放在这里是最保险的。
        await this.getNewArray(this.data)
        const parent = Array.from(new Set(this.getParent(obj)))
        this.$refs.tree.setCheckedKeys(
          getCheckedKeys
            .concat(this.checkStrictlyChildren ? children : [])
            .concat(this.checkStrictlyParent ? parent : [])
        )
      } else {
        let c = []
        for (let e of getCheckedKeys) {
          if (!children.includes(e)) {
            c.push(e)
          }
        }
        this.$refs.tree.setCheckedKeys([])
        this.$refs.tree.setCheckedKeys(c)
      }
      this.$emit('getCheckedKeys', this.$refs.tree.getCheckedKeys())
    }
  }
}
</script>
